package com.eunion.boot.security;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

/**
 * Spring security 权限验证.
 *  三种方法级权限控制
 * 1.securedEnabled: Spring Security’s native annotation
 * 2.jsr250Enabled: standards-based and allow simple role-based constraints @DenyAll @RolesAllowed({"USER", "ADMIN"})   @PermitAll 
 * 3.prePostEnabled: expression-based
 * @since 2017年1月1日
 */
@Configuration
@EnableWebSecurity
//@EnableGlobalMethodSecurity(prePostEnabled = true) //允许进入页面方法前检验
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;

	@Autowired
	AuthenticationManager authenticationManager;
	
	@Autowired
	private SysAuthenticationProvider provider;//自定义验证 

	@Autowired
	public void configAuthentication(AuthenticationManagerBuilder auth)
	    throws Exception {}

	@Override
	public void configure(WebSecurity web)
	    throws Exception {
		// 设置不拦截规则  
		web.ignoring().antMatchers("/assets/**", "/static/*", "/files/*");//, "/**/*.jsp"

	}

	/**
	 * 定义哪些URL需要被保护、哪些不需要被保护.
	 * @see http://docs.spring.io/spring-security/site/docs/4.2.1.RELEASE/reference/htmlsingle/#tutorial-sample
	 */
	@Override
	protected void configure(HttpSecurity http)
	    throws Exception {
		//允许iframe同域
		http.headers().frameOptions().sameOrigin();//.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN));
		//		http.headers()
		//	        .addHeaderWriter(new StaticHeaderWriter("X-Content-Security-Policy","default-src 'self'"))
		//	        .addHeaderWriter(new StaticHeaderWriter("X-WebKit-CSP","default-src 'self'"));
		// 开启默认登录页面  
		// http.formLogin();

		// 自定义accessDecisionManager访问控制器,并开启表达式语言 如下代码，然并卵  
		//http.exceptionHandling().accessDeniedPage("/admin/403");//accessDeniedHandler(accessDeniedServletHandler()).

		http
		//禁用CSRF保护  　Cross-site request forgery跨站请求伪造，也被称为“one click attack”或者session riding，通常缩写为CSRF或者XSRF，是一种对网站的恶意利用。
		.csrf().disable().authorizeRequests()
		//配置那些路径可以不用权限访问  
		.antMatchers("/static/*", "/assets/*", "/files/*", "/","/admin/login", "/admin/logout", "/admin/403","/verifyCode").permitAll()//not require any authentication. 
		//.antMatchers("/admin/*").authenticated();
		.anyRequest().authenticated();
		//		http.userDetailsService(userDetailsService)

		// 自定义登录页面  
//		http.formLogin().loginProcessingUrl("/admin/login").loginPage("/admin/login").defaultSuccessUrl("/admin/main").failureUrl("/admin/login?error=true").usernameParameter(
//		    "username").passwordParameter("password").permitAll().successHandler(loginSuccessHandler());
		
		http.formLogin()
        .loginProcessingUrl("/admin/login").loginPage("/admin/login").defaultSuccessUrl("/admin/main").failureUrl("/admin/login?error=true")
        .permitAll()
        .authenticationDetailsSource(authenticationDetailsSource)
        .successHandler(loginSuccessHandler());
		
		// 自定义注销  
		http.logout()//Provides logout support. 
		.logoutUrl("/admin/logout")//logout  3.x默认的注销拦截url为/j_spring_security_logout,而4.x则默认使用/logout
		.logoutSuccessUrl("/admin/login?message=logout")
		.invalidateHttpSession(true)
		.clearAuthentication(true)
		//			.logoutSuccessHandler(loginOutSuccessHandler())
		.permitAll();

//	  http.exceptionHandling()
//          .accessDeniedHandler(myAccessDeniedHandler)
//          .accessDeniedPage("/admin/accessDefine")
//          .and();
		
		// session管理   no use
		//		http.sessionManagement().sessionFixation().changeSessionId().maximumSessions(1).expiredUrl("/");

		// RemeberMe  no use 
		//		http.rememberMe().key("webmvc#FD637E6D9C0F1A5A67082AF56CE32485");
	}
	/* 
	*  
	* 这里可以增加自定义的投票器 
	*/
	//    @Bean(name = "accessDecisionManager")  
	//    public AccessDecisionManager accessDecisionManager() {  
	//        List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList();  
	//        decisionVoters.add(new RoleVoter());  
	//        decisionVoters.add(new AuthenticatedVoter());  
	//        decisionVoters.add(webExpressionVoter());// 启用表达式投票器  
	//        MyAccessDecisionManager accessDecisionManager = new MyAccessDecisionManager(decisionVoters);  
	//        return accessDecisionManager;  
	//    }  

	//	@Bean(name = "accessDeniedHandler")
	//	public SysAccessDeniedHandler accessDeniedServletHandler() {
	//		return new SysAccessDeniedHandler();
	//	}

	//http://docs.spring.io/spring-security/site/docs/4.2.1.RELEASE/reference/htmlsingle/#jc-logout
	@Bean
	public AuthenticationSuccessHandler loginSuccessHandler() {
		return new LoginSuccessHandler();
	}

	@Bean
	public LoginOutSuccessHandler loginOutSuccessHandler() {
		return new LoginOutSuccessHandler();
	}

	//	@Autowired
	//	public void configureGlobal(AuthenticationManagerBuilder auth)
	//	    throws Exception {
	//		auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
	//	}
	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth)
	    throws Exception {
		//将验证过程交给自定义验证工具
		auth.authenticationProvider(provider);
		// auth.inMemoryAuthentication().withUser("ram").password("ram123").roles("ADMIN"); 
	}
}
